package cn.iotab.iotkit.server.demo.controller;

import cn.iotab.iotkit.server.demo.device.AppService;
import cn.iotab.iotkit.transport.api.access.device.DeviceOperator;
import cn.iotab.iotkit.transport.api.access.model.custom.ProtocolConstant;
import cn.iotab.iotkit.transport.api.access.model.custom.firmware.PushUpgradeFirmwareMessage;
import cn.iotab.iotkit.transport.api.access.model.custom.firmware.PushUpgradeFirmwareMessageReply;
import cn.iotab.iotkit.transport.api.access.model.custom.function.FunctionInvokeMessage;
import cn.iotab.iotkit.transport.api.access.model.custom.function.FunctionInvokeMessageReply;
import cn.iotab.iotkit.transport.api.access.model.custom.property.PropertyPushMessage;
import cn.iotab.iotkit.transport.api.access.model.custom.property.PropertyPushMessageReply;
import cn.iotab.iotkit.transport.api.access.model.custom.property.PropertyReadMessage;
import cn.iotab.iotkit.transport.api.access.model.custom.property.PropertyReadMessageReply;
import cn.iotab.iotkit.transport.api.access.model.message.CommonDeviceMessage;
import cn.iotab.iotkit.transport.api.access.model.message.DeviceMessageReply;
import cn.iotab.iotkit.transport.api.common.util.AsyncCallbackTemplate;
import com.alibaba.fastjson.JSONObject;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Arrays;

@Slf4j
@Controller
@ResponseBody
@RequestMapping("/device")
public class DeviceController {

    //测试用设备信息，测试时订阅相关topic
    //v1/platform/post/device/aa/bb
    //v1/platform/reply/device/aa/bb


    @Resource
    private AppService appService;

    private DeviceOperator deviceOperator;

    @PostConstruct
    public void init() {
        deviceOperator = appService.getDeviceOperator();
    }

    private void setCommonInfo(CommonDeviceMessage message, String productKey, String deviceId) {
        message.setProductKey(productKey);
        message.setDeviceId(deviceId);
        message.setMessageId("123");//这里为了测试方便，ID都使用相同的。实际使用中同一设备不同消息的ID应该不同
        message.setMessageVersion(ProtocolConstant.MSG_VERSION_1_0);
        message.setNeedAck();
    }

    private static void logReply(ListenableFuture<? extends DeviceMessageReply> replyFuture, String opKey) {
        AsyncCallbackTemplate.withCallbackDirect(replyFuture,
                reply -> log.info("{} receive reply success, reply:{}", opKey, reply.toOriginMessageReply()),
                ex -> log.error("{} occurs exception", opKey, ex));
    }

    /**
     * 获取设备属性、配置、参数
     */
    @RequestMapping("/getProperties")
    public void getDeviceProperties(@RequestParam(name = "productKey") String productKey,
                                    @RequestParam(name = "deviceId") String deviceId) {
        PropertyReadMessage message = new PropertyReadMessage();
        message.setPropertySuffix("read.state");
        setCommonInfo(message, productKey, deviceId);
        message.addProperties(Arrays.asList("key1", "key2"));
        //
        ListenableFuture<PropertyReadMessageReply> replyFuture = deviceOperator.getProperty(message);
        logReply(replyFuture, "controller getProperties");
    }

    /**
     * 向设备推送 配置参数
     */
    @RequestMapping("/pushProperties")
    public void pushDeviceProperties(@RequestParam(name = "productKey") String productKey,
                                     @RequestParam(name = "deviceId") String deviceId) {
        PropertyPushMessage message = new PropertyPushMessage();
        message.setPropertySuffix("write.param");
        setCommonInfo(message, productKey, deviceId);
        message.addProperty("key1", "value1").addProperty("key2", "value2");
        ListenableFuture<PropertyPushMessageReply> replyFuture = deviceOperator.pushProperty(message);
        logReply(replyFuture, "controller pushProperties");
    }

    /**
     * 调用设备功能，比如关门，亮灯
     */
    @RequestMapping("/invokeFunction")
    public void invokeFunction(@RequestParam(name = "productKey") String productKey,
                               @RequestParam(name = "deviceId") String deviceId) {
        FunctionInvokeMessage message = new FunctionInvokeMessage();
        setCommonInfo(message, productKey, deviceId);
        message.setFunctionId("myFunction");
        message.setJsonParam(new JSONObject());
        ListenableFuture<FunctionInvokeMessageReply> replyFuture = deviceOperator.invokeFunction(message);
        logReply(replyFuture, "controller invokeFunction");
    }

    /**
     * 推送固件升级
     */
    @RequestMapping("/pushUpgrade")
    public void pushUpgrade(@RequestParam(name = "productKey") String productKey,
                            @RequestParam(name = "deviceId") String deviceId) {
        PushUpgradeFirmwareMessage message = new PushUpgradeFirmwareMessage();
        setCommonInfo(message, productKey, deviceId);
        message.setUrl("http://xxx");
        message.setVersion("1.1.1");
        message.setSize(1234);
        message.setNoNeedAck();
        ListenableFuture<PushUpgradeFirmwareMessageReply> replyFuture = deviceOperator.pushUpgradeFirmware(message);
        logReply(replyFuture, "controller pushUpgrade");
    }

    /**
     * 断开设备连接
     */
    @RequestMapping("/disconnect")
    public void disconnect(@RequestParam(name = "productKey") String productKey,
                           @RequestParam(name = "deviceId") String deviceId) {
        log.info("controller disconnect device {}_{}", productKey, deviceId);
        deviceOperator.disconnect(productKey, deviceId, "manual close");
    }
}
